#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define MSG_SIZE (8 + 4 + 4096) // src_tid (8 bytes) + seq (4 bytes) + padding (4096 bytes)
#define PIPE_NAME "/tmp/client_server_pipe"

// 负指数分布随机数生成
double exponential_random(double lambda) {
    double u = (double)rand() / RAND_MAX;
    return -log(1 - u) / lambda;
}

// 生产者线程函数
void* producer_thread(void* arg) {
    int id = *(int*)arg;
    double lambda = *(double*)((char*)arg + sizeof(int));
    int seq = 0;
    int fd = open(PIPE_NAME, O_WRONLY);
    if (fd < 0) {
        perror("Open pipe failed");
        return NULL;
    }

    char msg[MSG_SIZE];
    while (1) {
        // 构造消息
        memset(msg, 0, MSG_SIZE);
        *(long long*)msg = (long long)id; // src_tid
        *(int*)(msg + 8) = seq++;         // seq
        // 剩余4096字节已由memset填充为0

        // 写入管道
        if (write(fd, msg, MSG_SIZE) != MSG_SIZE) {
            perror("Write to pipe failed");
            break;
        }

        // 负指数分布间隔
        double interval = exponential_random(lambda);
        usleep((int)(interval * 1e6)); // 转换为微秒
    }
    close(fd);
    return NULL;
}

int main(int argc, char* argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <n> <lambda>\n", argv[0]);
        return 1;
    }

    int n = atoi(argv[1]);          // 生产者线程数
    double lambda = atof(argv[2]);  // 负指数分布参数
    srand(time(NULL));

    // 创建命名管道
    mkfifo(PIPE_NAME, 0666);

    // 创建生产者线程
    pthread_t* threads = malloc(n * sizeof(pthread_t));
    char* args = malloc(n * (sizeof(int) + sizeof(double)));
    for (int i = 0; i < n; i++) {
        *(int*)(args + i * (sizeof(int) + sizeof(double))) = i;
        *(double*)(args + i * (sizeof(int) + sizeof(double)) + sizeof(int)) = lambda;
        pthread_create(&threads[i], NULL, producer_thread, args + i * (sizeof(int) + sizeof(double)));
    }

    // 主线程等待
    for (int i = 0; i < n; i++) {
        pthread_join(threads[i], NULL);
    }

    free(threads);
    free(args);
    unlink(PIPE_NAME);
    return 0;
}
